﻿Imports System.Linq.Expressions
Imports System.Data
Imports System.Runtime.InteropServices


Public Class LocalExpression

    Protected Local As Func(Of Double)

    Protected Friend Expr As Expression
    Protected Friend Params As IEnumerable(Of ParameterExpression)

    Protected GetString As Func(Of String)


    Public Shared Widening Operator CType(ByVal value As Double) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Constant(value)
        result.Params = New ParameterExpression() {}
        result.GetString = Function() value.ToString(Globalization.CultureInfo.InvariantCulture)
        Return result
    End Operator


    Public Shared Operator +(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.AddChecked(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " + " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator -(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.SubtractChecked(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " - " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator /(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.Divide(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " / " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator *(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.MultiplyChecked(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " * " & right.GetString() & ")"
        Return result
    End Operator

    Public Shared Operator <(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.LessThan(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " < " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator <=(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.LessThanOrEqual(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " <= " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator >(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.GreaterThan(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " > " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator >=(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.GreaterThanOrEqual(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " >= " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator =(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.Equal(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " = " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator <>(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.NotEqual(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " <> " & right.GetString() & ")"
        Return result
    End Operator

    Public Shared Operator And(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.And(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " And " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator Or(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.Or(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " Or " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator Xor(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.ExclusiveOr(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " Xor " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator Not(ByVal left As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = left.Params.ToArray()
        result.Expr = Expression.Not(left.Expr)
        result.GetString = Function() "( Not " & left.GetString() & ")"
        Return result
    End Operator

    Public Shared Operator Mod(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.Modulo(left.Expr, right.Expr)
        result.GetString = Function() "(" & left.GetString() & " % " & right.GetString() & ")"
        Return result
    End Operator
    Public Shared Operator ^(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Params = Enumerable.Union(left.Params, right.Params)
        result.Expr = Expression.Power(left.Expr, right.Expr)
        Return result
    End Operator

    Public Shared Operator Like(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New ModelExpression
        result.YExpr = left
        result.YExpr = right
        result.Expr = Expression.Variable(GetType(Double))
        result.Params = Enumerable.Union(Enumerable.Union(left.Params, right.Params), New ParameterExpression() {result.Expr})
        Return result
    End Operator
    Public Shared Function Choose(ByVal condition As LocalExpression, ByVal vt As LocalExpression, ByVal vf As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Condition(condition.Expr, vt.Expr, vf.Expr)
        result.Params = Enumerable.Union(Enumerable.Union(vt.Params, vf.Params), condition.Params)
        result.GetString = Function() "IIF(" & condition.GetString() & " , " & vt.GetString() & " , " & vf.GetString() & ")"
        Return result
    End Function
    Public Shared Function Log(ByVal left As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Call( _
            GetType(Math), _
            "Log", _
             Nothing, _
              left.Expr)

        result.Params = left.Params.ToArray()
        Return result
    End Function
    Public Shared Function Log10(ByVal left As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Call( _
            GetType(Math), _
            "Log10", _
             Nothing, _
              left.Expr)

        result.Params = left.Params.ToArray()
        Return result
    End Function
    Public Shared Function Log(ByVal left As LocalExpression, ByVal right As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Call( _
            GetType(Math), _
            "Log", _
             Nothing, _
              left.Expr, right.Expr)

        result.Params = Enumerable.Union(left.Params, right.Params)
        Return result
    End Function
    Public Shared Function Exp(ByVal left As LocalExpression) As LocalExpression
        Dim result As New LocalExpression
        result.Expr = Expression.Call( _
            GetType(Math), _
            "Exp", _
             Nothing, _
              left.Expr)

        result.Params = left.Params.ToArray()
        Return result
    End Function

    'Public Shared Function Choose(ByVal condition As LocalExpression, ByVal ParamArray exprs() As LocalExpression) As LocalExpression
    '    Dim result As New LocalExpression

    '    Return result
    'End Function


    Private Class ModelExpression
        Inherits LocalExpression

        Friend XExpr As LocalExpression
        Friend YExpr As LocalExpression

    End Class
End Class

Public Class LocalParamTable
    Inherits LocalExpression

    Private _Vars As String() = Nothing
    Friend _Keys(,) As Integer = Nothing
    Friend _Values() As Double = Nothing
    Private _ComputeValues() As Double = Nothing
    Private _p1 As String

    Friend _KeysOne() As Integer = Nothing


    'Public Class Key
    '    Private owner As LocalParamTable

    '    Sub New(ByVal owner As LocalParamTable, ByVal index As Integer)
    '        Me.owner = owner
    '        Me.index = index
    '    End Sub

    '    Public Overrides Function GetHashCode() As Integer
    '        Return MyBase.GetHashCode()
    '    End Function

    '    Public Overrides Function Equals(ByVal obj As Object) As Boolean
    '        Dim other As Key = obj
    '        For i As Integer = 0 To owner._Vars.Length - 1
    '            If other.owner._Keys(index
    '        Next
    '        Return True
    '    End Function
    'End Class

    Sub New(ByVal p1 As String)
        ' TODO: Complete member initialization 
        _p1 = p1
        Expr = Expression.Variable(GetType(Double), p1)
        Params = New ParameterExpression() {Expr}
    End Sub

    ReadOnly Property ParamExpr As ParameterExpression
        Get
            Return Expr
        End Get
    End Property

    Public Sub Reset()
        _ComputeValues = Nothing
    End Sub

    Friend KeyValueProvider As KeyValueprovider

    Sub New()
        Expr = Expression.Variable(GetType(Double))
        Params = New ParameterExpression() {Expr}

    End Sub

    Public Property Value As Double
        Get
            Return _Values(0)
        End Get
        Set(ByVal v As Double)
            For i As Integer = 0 To _Values.Length - 1
                _Values(i) = v
            Next
        End Set
    End Property
    Public Property Value(ByVal keyindex As Integer) As Double
        Get
            Return _Values(keyindex)
        End Get
        Set(ByVal value As Double)
            _Values(keyindex) = value
        End Set
    End Property
    Public Property Value(ByVal ParamArray keys() As Integer) As Double
        Get
            For i As Integer = 0 To _Values.Length - 1
                If KeyEquals(i, keys) Then
                    Return _Values(i)
                End If
            Next
            Return Double.NaN
        End Get
        Set(ByVal v As Double)
            For i As Integer = 0 To _Values.Length - 1
                If KeyEquals(i, keys) Then
                    _Values(i) = v
                End If
            Next
        End Set
    End Property

    Private Function KeyEquals(ByVal id As Integer, ByVal values() As Integer) As Boolean
        For i As Integer = 0 To Math.Min(_Keys.GetLength(1) - 1, values.Length - 1)
            If _Keys(id, i) <> values(i) Then
                Return False
            End If
        Next
        Return True
    End Function

    'Public Shared Operator +(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    'If left._ComputeValues Is Nothing Then
    '    '    ReDim left._ComputeValues(left._Values.Length - 1)
    '    '    Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    'End If
    '    'For i As Integer = 0 To left._Values.Length - 1
    '    '    left._ComputeValues(i) += right
    '    'Next
    '    'Return left

    'End Operator
    'Public Shared Operator -(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) -= right
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator *(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) *= right
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator /(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) /= right
    '    Next
    '    Return left
    'End Operator

    'Public Shared Operator +(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) += left
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator -(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) -= left
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator *(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) *= left
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator /(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) /= left
    '    Next
    '    Return right
    'End Operator

    'Public Shared Operator >(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = left._ComputeValues(i) > right
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator >=(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = left._ComputeValues(i) >= right
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator <(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = left._ComputeValues(i) < right
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator <=(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = left._ComputeValues(i) <= right
    '    Next
    '    Return left
    'End Operator

    'Public Shared Operator >(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = left > right._ComputeValues(i)
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator >=(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = left >= right._ComputeValues(i)
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator <(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = left < right._ComputeValues(i)
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator <=(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = left <= right._ComputeValues(i)
    '    Next
    '    Return right
    'End Operator

    'Public Shared Operator =(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = (left = right._ComputeValues(i))
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator <>(ByVal left As Double, ByVal right As LocalParamTable) As LocalParamTable
    '    If right._ComputeValues Is Nothing Then
    '        ReDim right._ComputeValues(right._Values.Length - 1)
    '        Array.Copy(right._Values, right._ComputeValues, right._Values.Length)
    '    End If
    '    For i As Integer = 0 To right._Values.Length - 1
    '        right._ComputeValues(i) = (left <> right._ComputeValues(i))
    '    Next
    '    Return right
    'End Operator
    'Public Shared Operator =(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = (left._ComputeValues(i) = right)
    '    Next
    '    Return left
    'End Operator
    'Public Shared Operator <>(ByVal left As LocalParamTable, ByVal right As Double) As LocalParamTable
    '    If left._ComputeValues Is Nothing Then
    '        ReDim left._ComputeValues(left._Values.Length - 1)
    '        Array.Copy(left._Values, left._ComputeValues, left._Values.Length)
    '    End If
    '    For i As Integer = 0 To left._Values.Length - 1
    '        left._ComputeValues(i) = (left._ComputeValues(i) <> right)
    '    Next
    '    Return left
    'End Operator



    'Public Shared Function Choose(ByVal condition As Boolean, ByVal valuetrue As LocalParamTable, ByVal valuefalse As LocalParamTable) As LocalParamTable

    'End Function
    'Public Shared Function Choose(ByVal condition As LocalParamTable, ByVal valuetrue As LocalParamTable, ByVal valuefalse As LocalParamTable) As LocalParamTable
    '    Return condition
    'End Function
End Class

Public Structure ParamTableKey

    Public data() As Integer


End Structure

Public Class WorkTable

    Private data As DataSet

    '  Public datadynamic As New List(Of DynamicRow)

    Public Property IsReadonly As Boolean
    Public Property Columns As IList(Of Column)

    Private RowExpression As ParameterExpression = _
        Expression.Parameter(GetType(Row))

    Public Class Column
        Inherits LocalExpression

        Public Property Index As Integer
        Public Property Name As String
        Public Property Type As ColumnType
        Public Property Table As WorkTable

        Sub New(ByVal owner As WorkTable)
            Me.Table = owner
            Me.Expr = Expression.Property(owner.RowExpression, "Item", Expression.Constant(Me.Index))
            Me.Params = New ParameterExpression() {owner.RowExpression}
        End Sub

        Public Property Brothers As IList(Of ParameterColumn)
    End Class

    Public Class Parameter
        Inherits LocalExpression

        Public Property Index As Integer
        Public Property Name As String
        Public Property Type As ColumnType
        Public Property Dimension As Integer
        Public Property Table As WorkTable

        Public Property Columns As IList(Of ParameterColumn)

    End Class

    Public Class ParameterColumn
        Inherits Column

        Public Property Brother As Column
        Public Property Parameter As Parameter

        Sub New(ByVal owner As Parameter)
            MyBase.New(owner.Table)
            Me.Parameter = owner
        End Sub
        Sub New(ByVal owner As Parameter, ByVal brother As Column)
            MyBase.New(owner.Table)
            Me.Parameter = owner
            Me.Brother = brother
        End Sub

    End Class

    Public Class Row

        Public Property Index As Integer



        Default Public Property Item(ByVal col As Integer) As Double
            Get

            End Get
            Set(ByVal value As Double)

            End Set
        End Property
        Default Public Property Item(ByVal col As String) As Double
            Get

            End Get
            Set(ByVal value As Double)

            End Set
        End Property
        Default Public Property Item(ByVal col As Column) As Double
            Get

            End Get
            Set(ByVal value As Double)

            End Set
        End Property
        Default Public Property Item(ByVal col As Parameter) As Double
            Get

            End Get
            Set(ByVal value As Double)

            End Set
        End Property

    End Class

    Public Class ParameterRow

    End Class

    Public Enum ColumnType
        Int32
        Int64
        Float32
        Float64
        Bool
        DateTime
        TimeSpan
        Enumeration
        Mixed
    End Enum

    Public Function Compute(ByVal rowindex As Integer, ByVal functor As LocalExpression) As Object
        Dim f = Expression.Lambda(Of Func(Of Row, Double))(functor.Expr, functor.Params).Compile()
        Return f(New Row())
    End Function
End Class

Public Class DataSetAdapter
    Friend data As DataSet

    Friend main As MainTable
    Friend columns As New List(Of ColumnAdapter)
    Friend parameters As New List(Of Parameter)

    Sub New(ByVal table As DataTable, ByVal ParamArray ps() As String)

        data = New DataSet()

        main = New MainTable() With {.table = table}
        data.Tables.Add(table)
        For Each c In table.Columns
            columns.Add(New ColumnAdapter(c, Me))
        Next

        For Each s In ps
            Dim t = New DataTable(s)
            Dim idcol = t.Columns.Add("_ID_", GetType(Integer))
            idcol.AllowDBNull = False
            idcol.AutoIncrement = True
            idcol.Unique = True
            t.PrimaryKey = New DataColumn() {idcol}
            t.Columns.Add(s, GetType(Double))
            data.Tables.Add(t)
            t.Rows.Add(t.NewRow())
            parameters.Add(New Parameter(t.Columns(s), Me, s))
        Next

        Dim rtable = New DataTable("result_table")
        data.Tables.Add(rtable)
    End Sub

    Public Class MainTable
        Inherits Dynamic.DynamicObject

        Friend table As DataTable
        Friend columns As New List(Of ColumnAdapter)
        Friend RowExpression As System.Linq.Expressions.ParameterExpression = _
            Expression.Parameter(GetType(RowAdapter))


    End Class

    Public Class Parameter
        Inherits ColumnAdapter

        Friend Vars() As String


        Sub New(ByVal column As DataColumn, ByVal owner As DataSetAdapter, ByVal columnname As String)
            MyBase.New(column, owner)
            Me.GetString = Function()
                               If owner.data.Tables(columnname).Columns.Count > 2 Then
                                   Return "Parent(rel" & columnname & ")." & columnname
                               Else
                                   Return CDbl(owner.data.Tables(columnname).Rows(0)(columnname)).ToString(Globalization.CultureInfo.InvariantCulture)
                               End If
                           End Function
        End Sub
    End Class

    Public Class Result

        Friend table As DataTable

    End Class

    Public Class TableAdapter

    End Class

    Public Class ColumnAdapter
        Inherits LocalExpression

        Friend column As DataColumn

        Sub New(ByVal column As DataColumn, ByVal owner As DataSetAdapter)
            Me.column = column
            Me.Expr = Expression.Property(owner.main.RowExpression, "Item", Expression.Constant(Me.column.ColumnName))
            Me.Params = New ParameterExpression() {owner.main.RowExpression}
            Me.GetString = Function() column.ColumnName
        End Sub
    End Class

    Public Class RowAdapter

        Friend row As DataRow
        Friend isparent As Boolean = False

        Default Public Property Item(ByVal col As String) As Double
            Get
                Try
                    Return row(col)
                Catch ex As Exception
                    Try
                        Return row.GetParentRow("rel_" & col)(col)
                    Catch ex1 As Exception
                        Return Nothing
                    End Try
                End Try
            End Get
            Set(ByVal value As Double)
                Try
                    row(col) = value
                Catch ex As Exception
                    Try
                        row.GetParentRow("rel_" & col)(col) = value
                    Catch ex1 As Exception

                    End Try
                End Try
            End Set
        End Property
    End Class

    Sub AddCol(ByVal p As String, ByVal col As String)
        If data.Tables(p).Columns.Contains(col) Then Return

        If data.Relations.Contains("rel" & p) Then
            data.Relations.Remove("rel" & p)
            main.table.Constraints.Remove("rel" & p)
        End If


        Dim ccc = (From c As DataColumn In data.Tables(p).Columns
                  Where c.ColumnName <> "_ID_" And c.ColumnName <> p
                  Select c.ColumnName).ToList()

        ccc.Add(col)
        Dim O = 1

        data.Tables(p).Constraints.Clear()
        data.Tables.Remove(p)
      

        Dim t = main.table.DefaultView.ToTable(p, True, ccc.ToArray())
        For Each c As DataColumn In t.Columns
            c.ReadOnly = True
        Next

        Dim idcol = t.Columns.Add("_ID_", GetType(Integer))
        For i As Integer = 0 To t.Rows.Count - 1
            t.Rows(i)(idcol) = i
        Next
        idcol.ReadOnly = True

        idcol.AllowDBNull = False
        idcol.AutoIncrement = True
        idcol.Unique = True
        t.PrimaryKey = New DataColumn() {idcol}
        idcol.SetOrdinal(0)
        t.Columns.Add(p, GetType(Double))

        data.Tables.Add(t)

        Dim cc2 = (From c As DataColumn In data.Tables(p).Columns
                  Where c.ColumnName <> "_ID_" And c.ColumnName <> p
                  Select c.ColumnName)

        Dim parent As New List(Of DataColumn)
        Dim children As New List(Of DataColumn)

        For Each c In cc2
            parent.Add(t.Columns(c))
            children.Add(main.table.Columns(c))
        Next

        data.Relations.Add( _
            "rel" & p, _
             parent.ToArray(), _
             children.ToArray())

    End Sub

End Class


Public Structure MixedValue

    Public ValueInt32 As Int32
    Public ValueInt64 As Int32
    Public ValueFloat32 As Int32
    Public ValueFloat64 As Int32
    Public ValueInt As Int32
End Structure

Class KeyValueprovider

    'test

    Private data As Dictionary(Of String, String())
    Private Shared testdata As Integer(,) = New Integer(,) _
            { _
                {0, 0, 0}, _
                {0, 0, 1}, _
                {0, 1, 0}, _
                {0, 1, 1}, _
                {1, 0, 0}, _
                {1, 0, 1}, _
                {1, 1, 0}, _
                {1, 1, 1} _
            }

    Private Shared colmap As Dictionary(Of String, Integer)

    Public Shared Function GetValues(ByVal ParamArray vars() As String) As Integer(,)
        If colmap Is Nothing Then
            colmap = New Dictionary(Of String, Integer)()
            colmap.Add("col0", 0)
            colmap.Add("col1", 1)
            colmap.Add("col2", 2)
        End If

        Dim ids = (From e In vars Select colmap(e)).ToArray()

        If ids.Length = 1 Then
            Dim o = New Integer(,) {{0}, {1}}
            Return o
        End If
        If ids.Length = 3 Then
            Return testdata.Clone()
        End If
        If ids.Length = 1 Then
            Dim o = New Integer(,) _
            { _
                {0, 0}, _
                {0, 1}, _
                {1, 0}, _
                {1, 1} _
            }
        End If

        Return Nothing
    End Function
End Class
